/*
* Copyright (c) 2007 by Kirill Kolodyazhniy.
* See the file "license.terms" for information on usage and redistribution.
*/

#ifndef M_PTRPOLICY_H
#define M_PTRPOLICY_H

#ifdef _MSC_VER
#pragma warning(disable:4127)
#endif

#include "atomic.h"

#include <stdexcept>
#include <vector>

namespace Engine
{

	template<class T>
	class DefaultDelete
	{
	public:
		static void Delete(T** ptr){delete *ptr; *ptr = 0;}
	};

	template<class T>
	class ArrayDelete
	{
	public:
		static void Delete(T** ptr){delete[] *ptr; *ptr = 0;}
	};

	/**
	*   Extension for proxy reference counting object, to support weak references.
	*/	
	class WeakPtrExtension
	{
	public:
		
		WeakPtrExtension():m_count(0){}

		/**
		*   Increment reference counter.
        */
		void AddWeakRef(){AtomicIncrement(&m_count);}

		/**
		*   Decrement reference counter.      
        */
        void DelWeakRef(){AtomicDecrement(&m_count);}

		/**
		*   Return number of references.
        */
		long GetWeakCount()const {return m_count;}

	private:
		
		volatile long m_count;///< reference counter.
	};

	/**
	*   Extension for proxy reference counting object, to disable support weak references.
	*/
	class NoWeakPtrExtension
	{
	public:
		
		NoWeakPtrExtension(){}

		/**
		*   Increment reference counter.
        */
		void AddWeakRef(){}

		/**
		*   Decrement reference counter.      
        */
        void DelWeakRef(){}

		/**
		*   Return number of references.
        */
		long GetWeakCount()const {return 0;}	
	};

	/**
	*   Reference counter  helper.
	*/
	template<class WeakPolicy>
	class Counter: public WeakPolicy
	{
    public:
        /**
		*   Explicit constructor.
        */
         Counter():m_count(0){}

		/**
		*   Destructor.
        */
        ~Counter(){if(m_count < 0 || m_count > 0)throw 0;}

		/**
		*   Increment reference counter.
        */
		void AddRef(){AtomicIncrement(&m_count);}

		/**
		*   Decrement reference counter.
       	*   And destroy real object.
        */		
        void DelRef()
        {
			AtomicDecrement(&m_count);
			if(m_count < 0)throw 0;
        }		

		/**
		*   Return number of references.
        */
        long GetCount()const {return m_count;}
			

	private:

		volatile long m_count;///< reference counter.

    };
}

#endif
